import os
import time
import socket
from redis import StrictRedis, ConnectionPool
import threading
from functools import wraps
import requests
import json
"""
对IP状态进行定时检测，同时将未连接的信息发送给钉钉，部署在linux服务器上，使用crontab实现定时检测

"""

def info(arg):
    def _info(func):
        @wraps(func)
        def wrapper(*args, **kwargs):

            if arg == 'len':
                ret = func(*args, **kwargs)  #
                if ret:
                    c = len(ret[0])
                    print('等分长度:{} 拆分后列表长度:{}'.format(c, len(ret)))
                else:
                    print('拆分列表为空')
            elif arg == 'time':
                start = time.time()
                ret = func(*args, **kwargs)  # , **kwargs
                end = time.time()
                print('运行时间:{}'.format(end - start))
            return ret

        return wrapper

    return _info


class IPcheck(object):

    def __init__(self):
        super(IPcheck, self).__init__()
        self.ip_data = {}  # 检测当前ip对应的返回结果
        self.pool = ConnectionPool(host='192.168.1.83', port=6379, password='123456', db=0)
        self.rs = StrictRedis(connection_pool=self.pool)
        self.PORT = 2023
        self.BUFFER = 1024

    @info('len')
    def clip_list(self, a, c):
        """
        列表拆分
        :param a:
        :param c:
        :return:
        """
        clip_back = []
        if len(a) > c:
            for i in range(int(len(a) / c)):
                # print(i)
                clip_a = a[c * i:c * (i + 1)]
                clip_back.append(clip_a)
                # print(clip_a)
            # last
            last = a[int(len(a) / c) * c:]
            if last:
                clip_back.append(last)
        return clip_back

    def connect(self, ip):
        """
        检测电脑是否开机.一个坑使用 Host Unreachable 来判定就是一直为真
        :param ip:
        :return: 返回0则表示连接失败(关机),200表示客户端正在运行，404表示客户端没有运行
        """
        code = 404
        cmd = "ping {} -b -c2".format(ip)
        result = os.popen(cmd)
        text = result.read()
        result.close()
        # if '请求超时' in text or '无法访问目标主机' or 'Host Unreachable' in text:  # 无法访问目标主机
        if 'time=' not in text:
            # print('关机：',ip,text)
            code = 404
        else:
            # print('else:',ip)
            if self.isOn(ip):
                code = 200
            else:
                code = 503
        # if ip=='192.168.1.85':
            # da=self.isOn(ip)
            # print('85的结果:',code)
            # print(da)
        return code

    def isOn(self, ip):
        """
        传入ip，检测服务是否正在运行
        :param ip:
        :return:
        """
        print('尝试连接主机:',ip)
        if ip=='192.168.1.85':
            print('找到85了')
        data = None
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(0.55)

        try:
            sock.connect((ip, self.PORT))
            # print(sock._closed)
            msg = {'ask': 1}
            sock.send(str(msg).encode())
            back = sock.recv(self.BUFFER)
            data = back
            print('isOn:',data)
        except Exception as request_from_222_ERR:
            print('request failed,更新Redis状态')
            print(str(request_from_222_ERR))
        finally:
            sock.close()
        if data:
            return True
        else:
            return False
        # return data

    def check_list(self, ip_list):
        """
        对传入的ip_list进行循环检测结果,并更新全局ip_data信息
        :param ip_list: ['192.168.1.1', '192.168.1.2', '192.168.1.3', '192.168.1.4', '192.168.1.5']
        :return:
        """
        data = {}
        print('检测ip开始:', ip_list[0])
        for ip in ip_list:
            result = self.connect(ip)
            data[ip] = result
        self.ip_data.update(data)
        print('检测ip结束:', ip_list[0])

    @info('time')
    def check(self, a, c=5):
        """
        传入拆分后的ip_list
        :param clip_ip_list: [['192.168.1.1', '192.168.1.2', '192.168.1.3', '192.168.1.4', '192.168.1.5'],
        ['192.168.1.6', '192.168.1.7', '192.168.1.8', '192.168.1.9', '192.168.1.10'],...]
        :return:
        """
        clip_ip_list = self.clip_list(a, c)
        thread_list = []
        for ip_list in clip_ip_list:
            clipThread = threading.Thread(target=self.check_list, args=(ip_list,))
            thread_list.append(clipThread)
            clipThread.start()

        for t in thread_list:
            t.join()

        print('ip_data:', len(self.ip_data), self.ip_data)
        disconnect_list=self.get_404_ip(self.ip_data)
        self.rs.set('ip_list', str(self.ip_data))
        if disconnect_list:
            self.DD(disconnect_list)

    def get_404_ip(self,data):
        """
        获取404开机但没有连上去的ip显示
        :param data:
        :return:
        """
        disconnect_list=[]
        if data:
            for ip,status in data.items():
                if status==404:
                    disconnect_list.append(ip)
        return disconnect_list

    def DD(self,disconnect_list):
        """
        发送没有连接的信息到钉钉
        :param disconnect_list:开机但是没有连接的机器列表
        :return:
        """
        ip_list='\n'.join(disconnect_list)
        # 状态助手
        url = 'https://oapi.dingtalk.com/robot/send?access_token=5b29a465ccbecd6cbb82b8aae543a1fb36fb0ae9c21227eb3ee9b9896d85f6a3'
        #url = 'https://oapi.dingtalk.com/robot/send?access_token=1cc4cb4cdda998ecc50d4b6f2a12cba311766743506d0ef251e09da3321ff776'
        #肉丸子
        # url='https://oapi.dingtalk.com/robot/send?access_token=20bd797c399498ce673db5cebb20fdd4ed191c93a424f508f2961afb97e98a6f'
        HEADERS = {
        "Content-Type": "application/json ;charset=utf-8 "
        }
        # estring='吃！没有连接的ip:\n{}'.format(ip_list)
        report='报告:没有连接的ip:\n{}'.format(ip_list)
        # A=unicode(estring, "utf-8")
        String_textMsg = {"msgtype": "text","text": {"content":report}}
        String_textMsg = json.dumps(String_textMsg)
        res = requests.post(url, data=String_textMsg, headers=HEADERS)
        print(res.text)


if __name__ == '__main__':
    # ip_list = ['192.168.1.{}'.format(n) for n in range(1, 256)] #256
    ip_list=['192.168.1.85','192.168.1.88','192.168.1.93']
    ic = IPcheck()
    ic.check(ip_list, 2)


